/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 *
 */

import { HookArgMap, HookType } from '../../../../common/const/hook-const.js';
import { hvigorCore } from '../../../external/core/hvigor-core.js';
import { Consumer } from '../../../external/interface/consumer.js';
import { HvigorLogger } from '../../../log/hvigor-log.js';
import { DurationEvent } from '../../../metrics/event/duration-event.js';

const _log = HvigorLogger.getLogger('HvigorLifecycleHook');

/**
 * hvigor生命周期中的hook点存放对象
 */
export class HvigorLifecycleHook {
  private static instance: HvigorLifecycleHook;

  // 初始化阶段hook
  private configEvaluatedFnList: Consumer<HookArgMap[HookType.configEvaluated]>[] = [];
  private nodesInitializedFnList: Consumer<HookArgMap[HookType.nodesInitialized]>[] = [];

  // 配置阶段hook
  private beforeNodeEvaluateFnList: Consumer<HookArgMap[HookType.beforeNodeEvaluate]>[] = [];
  private afterNodeEvaluateFnList: Consumer<HookArgMap[HookType.afterNodeEvaluate]>[] = [];
  private nodesEvaluatedFnList: Consumer<HookArgMap[HookType.nodesEvaluated]>[] = [];
  private taskGraphResolvedFnList: Consumer<HookArgMap[HookType.taskGraphResolved]>[] = [];

  // 执行阶段hook
  private buildFinishedFnList: Consumer<HookArgMap[HookType.buildFinished]>[] = [];

  // 线程池相关的hook
  private onWatchWorkerMessageFnList: Consumer<HookArgMap[HookType.onWatchWorkerMessage]>[] = [];

  // 定义每个hook的运行策略
  private strategies: Record<HookType, Consumer<unknown>> = {
    [HookType.configEvaluated]: async (arg) => {
      await this.runFn(this.configEvaluatedFnList, arg as HookArgMap[HookType.configEvaluated]);
    },
    [HookType.nodesInitialized]: async (arg) => {
      await this.runFn(this.nodesInitializedFnList, arg as HookArgMap[HookType.nodesInitialized]);
    },
    [HookType.beforeNodeEvaluate]: async (arg) => {
      await this.runFn(this.beforeNodeEvaluateFnList, arg as HookArgMap[HookType.beforeNodeEvaluate]);
    },
    [HookType.afterNodeEvaluate]: async (arg) => {
      await this.runFn(this.afterNodeEvaluateFnList, arg as HookArgMap[HookType.afterNodeEvaluate]);
    },
    [HookType.nodesEvaluated]: async (arg) => {
      await this.runFn(this.nodesEvaluatedFnList, arg as HookArgMap[HookType.nodesInitialized]);
    },
    [HookType.taskGraphResolved]: async (arg) => {
      await this.runFn(this.taskGraphResolvedFnList, arg as HookArgMap[HookType.taskGraphResolved]);
    },
    [HookType.buildFinished]: async (arg) => {
      await this.runFn(this.buildFinishedFnList, arg as HookArgMap[HookType.buildFinished]);
    },
    [HookType.onWatchWorkerMessage]: async (arg) => {
      await this.runFn(this.onWatchWorkerMessageFnList, arg);
    },
  };

  /**
   * 实现单例模式
   */
  public static getInstance(): HvigorLifecycleHook {
    if (!HvigorLifecycleHook.instance) {
      HvigorLifecycleHook.instance = new HvigorLifecycleHook();
    }
    return HvigorLifecycleHook.instance;
  }

  // 运行一个储存hook的数组，数组中全都是包含一个函数的方法
  public async runFn<T>(array: Consumer<T>[], arg: T): Promise<void> {
    for (const fn of array) {
      if (fn) {
        await fn.bind(this)(arg);
      }
    }
  }

  /**
   *
   * 运行一个hook上所有的方法
   *
   * @param hookType hook点类型
   * @param arg 方法的入参
   * @param parentEvent
   */
  public async runHook<K extends HookType>(hookType: K, arg: HookArgMap[K], parentEvent: DurationEvent) {
    const hookEvent = parentEvent?.createSubEvent(`"${HookType[hookType]}" hook function`, '').start();
    try {
      await this.strategies[hookType].bind(this)(arg);
      hookEvent?.stop().setLog();
    } catch (e: unknown) {
      if (e instanceof Error) {
        hookEvent?.stop().setLog();
        _log.printErrorExit('FAILED_TO_EXECUTE_HOOK', [hookType, e.message], [[hookType]], e.stack);
      }
    }
  }

  public configEvaluated(fn: Consumer<HookArgMap[HookType.configEvaluated]>) {
    this.configEvaluatedFnList.push(fn);
  }
  public nodesInitialized(fn: Consumer<HookArgMap[HookType.nodesInitialized]>) {
    this.nodesInitializedFnList.push(fn);
  }

  public beforeNodeEvaluate(fn: Consumer<HookArgMap[HookType.beforeNodeEvaluate]>) {
    this.beforeNodeEvaluateFnList.push(fn);
  }

  public afterNodeEvaluate(fn: Consumer<HookArgMap[HookType.afterNodeEvaluate]>) {
    this.afterNodeEvaluateFnList.push(fn);
  }

  public nodesEvaluated(fn: Consumer<HookArgMap[HookType.nodesEvaluated]>) {
    this.nodesEvaluatedFnList.push(fn);
  }

  public taskGraphResolved(fn: Consumer<HookArgMap[HookType.taskGraphResolved]>) {
    this.taskGraphResolvedFnList.push(fn);
  }

  public buildFinished(fn: Consumer<HookArgMap[HookType.buildFinished]>) {
    this.buildFinishedFnList.push(fn);
  }

  public onWatchWorkerMessage(fn: Consumer<HookArgMap[HookType.onWatchWorkerMessage]>) {
    this.onWatchWorkerMessageFnList.push(fn);
  }

  public clear(): void {
    // 初始化阶段hook
    this.configEvaluatedFnList = [];
    this.nodesInitializedFnList = [];

    // 配置阶段hook
    this.beforeNodeEvaluateFnList = [];
    this.afterNodeEvaluateFnList = [];
    this.nodesEvaluatedFnList = [];
    this.taskGraphResolvedFnList = [];

    // 执行阶段hook
    this.buildFinishedFnList = [];
    this.onWatchWorkerMessageFnList = [];

    // 清除内部的钩子
    hvigorCore.clearHvigorInternalHookList();
  }
}
